package swing;

//SlidePuzzleGUI.java - GUI for SlidePuzzle
//Fred Swartz, 2003-May-10, 2004-May-3
//
//The SlidePuzzleGUI class creates a panel which 
//  contains two subpanels.
//  1. In the north is a subpanel for controls (just a button now).
//  2. In the center a graphics
//This needs a few improvements.  
//Both the GUI and Model define the number or puzzleSize and columns.
//       How would you set both from one place? 

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.LinkedList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import slidingPuzzle.Move;
import slidingPuzzle.SlidingPuzzle;

/////////////////////////////////////////////////// class SlidePuzzleGUI
//This class contains all the parts of the GUI interface
public class SlidePuzzleGUI extends JPanel {
 //=============================================== instance variables
 private GraphicsPanel    _puzzleGraphics;
 private static final int DEFAULT_PUZZLE_SIZE = 3;
 private SlidePuzzleModel _puzzleModel  = new SlidePuzzleModel(DEFAULT_PUZZLE_SIZE);
 private JTextField puzzleSizeOption = new JTextField(Integer.toString(DEFAULT_PUZZLE_SIZE));
 private int puzzleSize = 3;
 
 //end instance variables


 //====================================================== constructor
 public SlidePuzzleGUI() {
     //--- Create a button.  Add a listener to it.
     JButton newGameButton = new JButton("New Game");
     newGameButton.addActionListener(new NewGameAction());
     JLabel puzzleSizeLabel = new JLabel("Puzzle Size : ");
     
     JButton autoSolveButton = new JButton("Solve Problem");
     autoSolveButton.addActionListener(new AutoSolveAction());
     puzzleSizeOption.setSize(5,5);

     //--- Create control panel
     JPanel controlPanel = new JPanel();
     controlPanel.setLayout(new FlowLayout());
     controlPanel.add(newGameButton);
     controlPanel.add(puzzleSizeLabel);
     controlPanel.add(puzzleSizeOption);
     controlPanel.add(autoSolveButton);
     
     //--- Create graphics panel
     _puzzleGraphics = new GraphicsPanel();
	
     
     //--- Set the layout and add the components
     this.setLayout(new BorderLayout());
     this.add(controlPanel, BorderLayout.NORTH);
     this.add(_puzzleGraphics, BorderLayout.CENTER);
 }//end constructor


 //////////////////////////////////////////////// class GraphicsPanel
 // This is defined inside the outer class so that
 // it can use the outer class instance variables.
 class GraphicsPanel extends JPanel implements MouseListener {
//     private static final int puzzleSize = 3;
//     private static final int puzzleSize = 3;
     private static final int CELL_SIZE = 50; // Pixels
     private Font _biggerFont;
     
     
     //================================================== constructor
     public GraphicsPanel() {
    	 _biggerFont = new Font("SansSerif", Font.BOLD, CELL_SIZE/4);
    	 resetSize();
         this.setBackground(Color.black);
         this.addMouseListener(this);  // Listen own mouse events.
     }//end constructor
     
     public void resetSize() {
    	 this.setPreferredSize(
                 new Dimension(CELL_SIZE * puzzleSize, CELL_SIZE * puzzleSize));
     }
     
     //=======================================x method paintComponent
     public void paintComponent(Graphics g) {
         super.paintComponent(g);
         for (int r=0; r<puzzleSize; r++) {
             for (int c=0; c<puzzleSize; c++) {
                 int x = c * CELL_SIZE;
                 int y = r * CELL_SIZE;
                 String text = _puzzleModel.getFace(r, c);
                 if (text != null) {
                     g.setColor(Color.white);
                     g.fillRect(x+2, y+2, CELL_SIZE-2, CELL_SIZE-2);
                     g.setColor(Color.black);
                     g.setFont(_biggerFont);
                     g.drawString(text, x+20, y+(3*CELL_SIZE)/4);
                 }
             }
         }
     }//end paintComponent
     
     
     //======================================== listener mousePressed
     public void mousePressed(MouseEvent e) {
         //--- map x,y coordinates into a row and col.
         int col = e.getX()/CELL_SIZE;
         int row = e.getY()/CELL_SIZE;
         
         if (!_puzzleModel.moveTile(row, col)) {
             // moveTile moves tile if legal, else returns false.
             Toolkit.getDefaultToolkit().beep();
         }
         
         this.repaint();  // Show any updates to model.
     }//end mousePressed
     
     
     //========================================== ignore these events
     public void mouseClicked (MouseEvent e) {}
     public void mouseReleased(MouseEvent e) {}
     public void mouseEntered (MouseEvent e) {}
     public void mouseExited  (MouseEvent e) {}
 }//end class GraphicsPanel
 
 ////////////////////////////////////////// inner class NewGameAction
 public class NewGameAction implements ActionListener {
     public void actionPerformed(ActionEvent e) {
    	 puzzleSize = Integer.valueOf(puzzleSizeOption.getText());
    	 _puzzleModel = new SlidePuzzleModel(puzzleSize);
         _puzzleModel.reset();
         _puzzleGraphics.repaint();
         _puzzleGraphics.resetSize();
         JFrame parentFrame = (JFrame)SwingUtilities.getAncestorOfClass(JFrame.class, SlidePuzzleGUI.this);
         parentFrame.pack();
     }
 }//end inner class NewGameAction

 public class AutoSolveAction implements ActionListener{
	private Timer timer;
	private static final int DELAY = 100;
	public void actionPerformed(ActionEvent e) {

		SlidingPuzzle slidingPuzzle = new SlidingPuzzle(puzzleSize, _puzzleModel.getContents());
		final LinkedList<Move> moves = slidingPuzzle.autoSolve();
   	 	timer = new Timer(DELAY, new ActionListener() {
   	 		LinkedList<Move> m = moves;
   	 		@Override
   	 		public void actionPerformed(ActionEvent e) {
				 if (!m.isEmpty()) {
					 Move move = m.removeFirst();
		    		 _puzzleModel.exchangeTiles(move.getBegX(), move.getBegY(), move.getEndX(), move.getEndY());
		    		 _puzzleGraphics.repaint();
				 } else {
					 timer.stop();
				 }
   	 		}
   	 	});
   	 	timer.start();
	}
 }
 
}//end class SlidePuzzleGUI